package api

import (
	"TaskAssignmentSystem/internal/admin/dao"
	"TaskAssignmentSystem/internal/admin/services"
	services2 "TaskAssignmentSystem/internal/app/services"
	"TaskAssignmentSystem/internal/pkg/code"
	"TaskAssignmentSystem/internal/pkg/middleware/handler"
	"TaskAssignmentSystem/internal/pkg/middleware/mysqlhandler"
	"TaskAssignmentSystem/internal/pkg/modelbase"
	"TaskAssignmentSystem/pkg/oss"
	"TaskAssignmentSystem/pkg/timehandler"
	"TaskAssignmentSystem/pkg/utils"
	"errors"
	"fmt"
	"github.com/go-the-way/exl"
	"github.com/kataras/iris/v12"
	"github.com/tealeg/xlsx"
	"github.com/wxnacy/wgo/arrays"
	"github.com/xuri/excelize/v2"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"time"
)

// @Summary 批量导入用户
// @Description 批量导入用户
// @Tags 用户
// @Accept multipart/form-data
// @Produce application/json
// @param Accept-Version header string true "1.0.0"
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param file formData file true "批量导入用户参数"
// @Success 200 {object} utils.Response --> 成功后返回数据结构
// @Failure 400 {object} utils.ResponseError --> 失败后返回数据结构
// @Router /admin/user/excel/imports [post]
func SystemUserImportsHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	fileByte, err := ioutil.ReadAll(file) //获取上传文件字节流
	if err != nil {
		fmt.Println(err)
	}
	xlFile, err := xlsx.OpenBinary(fileByte)
	if err != nil {
		fmt.Printf("open failed: %s\n", err)
	}
	titles := []string{"账号前缀", "团队编号", "编号", "密码", "手机号", "姓名", "登录权限（0：注销；1：正常；2：封禁）", "项目领取限制（项目ID，领取上限，领取下限）"}
	var user dao.Common[dao.SystemUser]
	var res ImportsResponse
	for _, sheet := range xlFile.Sheets {

		for i, row := range sheet.Rows {
			var errListLength = len(res.ErrList)
			//判断excel格式对不对
			if i == 0 {
				for j, cell := range row.Cells {
					if strings.TrimSpace(cell.String()) != titles[j] {
						ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: fmt.Sprintf("文件表头格式不对,表头%s的名称有误", cell.String())})
						return
					}
				}
			}

			//从第三行开始
			if i >= 2 {
				res.TotalRows += 1
				var rowsList []string
				var userObj dao.SystemUser
				var row_data string
				for j, cell := range row.Cells {
					text := strings.TrimSpace(cell.String())
					row_data += text
					if text == "" && j < len(titles) {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   j + 1,
							Reason: fmt.Sprintf("第%d行字段%s的值不能为空", i+1, titles[j]),
						})
					}
					rowsList = append(rowsList, text)
				}
				if strings.TrimSpace(row_data) == "" {
					res.TotalRows -= 1
					break
				}
				if len(rowsList) < len(titles) {
					for k := len(rowsList); k < len(titles); k++ {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   k + 1,
							Reason: fmt.Sprintf("第%d行字段%s的值不能为空", i+1, titles[k]),
						})
					}
					res.FailRows += 1
					continue
				}

				userObj.UserNamePrefix = rowsList[0]
				userObj.TeamNumber = rowsList[1]
				userObj.UserNumber = rowsList[2]
				userObj.UserId = fmt.Sprintf("%s%s%s", userObj.UserNamePrefix, userObj.TeamNumber, userObj.UserNumber)
				userObj.PassWord = utils.Base64Encode(rowsList[3])
				userObj.Phone = rowsList[4]
				userObj.RealName = rowsList[5]
				if rowsList[6] != "" {
					userObj.Status, err = strconv.Atoi(rowsList[6])
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   6 + 1,
							Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, titles[6]),
						})
					}
					if arrays.Contains([]int{0, 1, 2}, userObj.Status) == -1 {
						res.ErrList = append(res.ErrList, code.ImportError{
							Sheet:  sheet.Name,
							Number: i + 1,
							Cell:   6 + 1,
							Reason: fmt.Sprintf("第%d行字段%s的值非有效值", i+1, titles[6]),
						})
					}
				}
				if rowsList[7] != "" {
					for _, item := range strings.Split(rowsList[7], "；") {
						if strings.TrimSpace(item) == "" {
							continue
						}
						items := strings.Split(item, "，")
						if len(items) != 3 {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   7 + 1,
								Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, titles[7]),
							})
							continue
						}
						lowerLimit, err := strconv.Atoi(strings.TrimSpace(items[2]))
						if err != nil {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   7 + 1,
								Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, titles[7]),
							})
						}
						limit, err := strconv.Atoi(strings.TrimSpace(items[1]))
						if err != nil {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   7 + 1,
								Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, titles[7]),
							})
						}
						if lowerLimit > limit {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   6 + 1,
								Reason: fmt.Sprintf("第%d行-%d最低下限不能超过最高上限", i+1, 7),
							})
						}
						userObj.SystemUserRestriction = append(userObj.SystemUserRestriction, modelbase.SystemUserRestriction{
							ProjectId:  strings.TrimSpace(items[0]),
							LowerLimit: lowerLimit,
							Limit:      limit,
						})
					}
				}
				if len(res.ErrList) > errListLength {
					if len(res.ErrList)-errListLength >= len(titles) {
						break
					} else {
						res.FailRows += 1
						continue
					}
				}
				if err := user.CreateOne(userObj).Error; err != nil {

					switch mysqlhandler.MysqlErrCode(err) {
					case mysqlhandler.ErrDuplicateEntryCode:
						res.ErrList = append(res.ErrList, code.ImportError{Number: i + 1, Reason: "该条数据已经存在,请检查用户Id和手机号码是否已经存在"})
					default:
						res.ErrList = append(res.ErrList, code.ImportError{Number: i + 1, Reason: err.Error()})
					}
					res.FailRows += 1
					continue
				}
			}
		}
	}
	res.SuccessRows = res.TotalRows - res.FailRows
	ctx.JSON(utils.Response{
		Code:    200,
		Message: "ok",
		Data:    res,
	})
	return
}

type SystemUserImportsNew struct {
	UserId                    string `excel:"用户ID(必填)"`                                         //用户Id
	TeamNumber                string `excel:"团队编号(选填)"`                                         //团队编号(选填)
	UserNumber                string `excel:"编号（选填）"`                                           //用户编号
	NickName                  string `excel:"昵称(选填)"`                                           //昵称
	RealName                  string `excel:"姓名(选填)"`                                           //姓名
	IsAuthentication          string `excel:"实名状态(0表示未实名，1表示已实名）（选填)"`                          //是否实名认证，0 未认证;1 已认证;
	IdCardNumber              string `excel:"身份证号码（选填）"`                                        //身份证号码
	Phone                     string `excel:"手机号(选填)"`                                          //手机号
	Email                     string `excel:"邮箱（选填）"`                                           //邮箱
	PassWord                  string `excel:"密码(选填)"`                                           //密码
	AlipayAccount             string `excel:"支付宝(选填)"`                                          //支付宝账号
	DeliveryAddress           string `excel:"收货地址(选填)"`                                         //收货地址
	Introduction              string `excel:"个人简介(选填)"`                                         //简介
	Status                    string `excel:"登录权限（0：注销；1：正常；2：封禁）(选填)"`                         //0 注销;1 正常; 2 封禁
	SystemUserRestriction     string `excel:"项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)"` //项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)
	SystemUserRestrictionType string `excel:"权限变更类型（1：新增权限；2：删除权限；3：覆盖权限）(选填)"`                 //权限变更类型（1：新增权限；2：删除权限；3：覆盖权限）(选填)
	Balance                   string `excel:"强制变更芝草数量（选填）（不填表示不修改）（填了则修改芝草为此数值）"`               //强制变更芝草数量（选填）（不填表示不修改）（填了则修改芝草为此数值）
	BalanceLog                string `excel:"强制变更芝草数量通知文本"`                                     //强制变更芝草数量通知文本
}

func (*SystemUserImportsNew) Configure(rc *exl.ReadConfig) {}

func NewSystemUserBatchUpdateHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	if models, err := exl.Read[*SystemUserImportsNew](file); err != nil {
		fmt.Println("read excel err:" + err.Error())
	} else {
		fmt.Printf("read excel num: %d\n", len(models))
		var userServe services.UserService
		var userDao dao.Common[dao.SystemUser]
		var commonDao dao.Common[dao.SystemUserBalanceLog]
		index := 0
		var res ImportsResponse
		for i, model := range models {
			//从第二行开始读取
			if i == 0 {
				continue
			}
			res.TotalRows += 1
			var errListLength = len(res.ErrList)
			//var userObj dao.SystemUser
			userObj, err := userDao.First(map[string]interface{}{"user_id": model.UserId})
			if err != nil {
				continue
			}
			userObj.SystemUserRestriction = nil
			//检查user基本信息
			if model.UserId != "" {
				userObj.UserId = model.UserId
			}
			if model.TeamNumber != "" {
				userObj.TeamNumber = model.TeamNumber
			}
			if model.UserNumber != "" {
				userObj.UserNumber = model.UserNumber
			}
			if model.NickName != "" {
				userObj.NickName = model.NickName
			}
			if model.RealName != "" {
				userObj.RealName = model.RealName
			}
			if model.IsAuthentication != "" {
				userObj.IsAuthentication, err = strconv.Atoi(model.IsAuthentication)
				if err != nil {
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Cell:   5 + 1,
						Reason: "实名状态(0表示未实名，1表示已实名）数据格式不对",
					})
					continue
				}
			}
			if model.IdCardNumber != "" {
				userObj.IdCardNumber = model.IdCardNumber
			}
			if model.Phone != "" {
				userObj.Phone = model.Phone
			}
			if model.Email != "" {
				userObj.Email = model.Email
			}
			if model.PassWord != "" {
				userObj.PassWord = utils.Base64Encode(model.PassWord)
			}
			if model.AlipayAccount != "" {
				userObj.AlipayAccount = model.AlipayAccount
			}
			if model.DeliveryAddress != "" {
				userObj.DeliveryAddress = model.DeliveryAddress
			}
			if model.Introduction != "" {
				userObj.Introduction = model.Introduction
			}
			if model.Status != "" {
				userObj.Status, err = strconv.Atoi(model.Status)
				if err != nil {
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Cell:   14,
						Reason: "登录权限（0：注销；1：正常；2：封禁）(选填)数据格式不对",
					})
					continue
				}
			}
			if model.SystemUserRestriction != "" {
				for _, item := range strings.Split(model.SystemUserRestriction, "；") {
					if strings.TrimSpace(item) == "" {
						continue
					}
					items := strings.Split(item, ",")
					if len(items) != 6 {
						items = strings.Split(item, "，")
						if len(items) != 6 {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   15,
								Reason: fmt.Sprintf("第%d行-%d列数据格式不对", i+1, 15),
							})
							break
						}
					}
					limit, err := strconv.Atoi(strings.TrimSpace(items[1]))
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   15,
							Reason: fmt.Sprintf("第%d行-%d列数据格式不对", i+1, 15),
						})
						break
					}
					lowerLimit, err := strconv.Atoi(strings.TrimSpace(items[2]))
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   15,
							Reason: fmt.Sprintf("第%d行-%d列数据格式不对", i+1, 15),
						})
						break
					}

					if lowerLimit > limit {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   15,
							Reason: fmt.Sprintf("第%d行-%d最低下限不能超过最高上限", i+1, 15),
						})
						break
					}
					cd, err := strconv.Atoi(strings.TrimSpace(items[3]))
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   15,
							Reason: fmt.Sprintf("第%d行-%d列数据格式不对", i+1, 15),
						})
						break
					}

					dayLimit, err := strconv.Atoi(strings.TrimSpace(items[4]))
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   15,
							Reason: fmt.Sprintf("第%d行-%d列数据格式不对", i+1, 15),
						})
						break
					}
					dayGiveUpLimit, err := strconv.Atoi(strings.TrimSpace(items[5]))
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   15,
							Reason: fmt.Sprintf("第%d行-%d列数据格式不对", i+1, 15),
						})
						break
					}
					userObj.SystemUserRestriction = append(userObj.SystemUserRestriction, modelbase.SystemUserRestriction{
						ProjectId:      strings.TrimSpace(items[0]),
						LowerLimit:     lowerLimit,
						Limit:          limit,
						Cd:             uint(cd),
						DayLimit:       uint(dayLimit),
						DayGiveUpLimit: uint(dayGiveUpLimit),
					})
				}
			}
			var mouthed int
			if model.SystemUserRestrictionType != "" {
				mouthed, err = strconv.Atoi(model.SystemUserRestrictionType)
				if err != nil {
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Cell:   16,
						Reason: "权限变更类型（1：新增权限；2：删除权限；3：覆盖权限）(选填)数据格式不对",
					})
				}
				if arrays.Contains([]int{3, 1, 2}, mouthed) == -1 {
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Cell:   16,
						Reason: "权限变更类型（1：新增权限；2：删除权限；3：覆盖权限）(选填)数据格式不对",
					})
				}
			}

			isLog := false
			if model.Balance != "" {
				userObj.Balance, err = strconv.ParseFloat(model.Balance, 64)
				if err != nil {
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Cell:   16,
						Reason: "强制变更芝草数量（选填）（不填表示不修改）（填了则修改芝草为此数值）数据格式不对",
					})
					break
				}
				isLog = true
			}
			if len(res.ErrList) > errListLength {
				res.FailRows += 1
				continue
			}
			if err := userServe.NewExcelBatchUpdate(userObj, mouthed); err != nil {
				switch mysqlhandler.MysqlErrCode(err) {
				case mysqlhandler.ErrDuplicateEntryCode:
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Reason: "该条数据已经存在，请检查用户Id或手机号码是否已经存在系统中！"})
				default:
					res.ErrList = append(res.ErrList, code.ImportError{
						Number: i + 1,
						Reason: err.Error()})
				}
				res.FailRows += 1
				continue
			}
			if isLog {
				var log dao.SystemUserBalanceLog
				log.UserId = userObj.UserId
				log.TeamNumber = userObj.TeamNumber
				log.RemainAmount = userObj.Balance
				log.Amount = userObj.Balance
				log.LogType = 1
				log.BusinessType = 3
				log.Remark = model.BalanceLog
				commonDao.CreateOne(log)
			}

			index++
		}
		ctx.JSON(utils.Response{
			Code:    200,
			Message: "ok",
			Data:    res,
		})
		return
	}
}

// @Summary 批量更新用户
// @Description 批量更新用户
// @Tags 用户
// @Accept multipart/form-data
// @Produce application/json
// @param Accept-Version header string true "1.0.0"
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param file formData file true "批量更新用户参数"
// @Success 200 {object} utils.Response --> 成功后返回数据结构
// @Failure 400 {object} utils.ResponseError --> 失败后返回数据结构
// @Router /admin/user/excel/batch_update [post]
func SystemUserBatchUpdateHandler(ctx iris.Context) {

	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	fileByte, err := ioutil.ReadAll(file) //获取上传文件字节流
	if err != nil {
		fmt.Println(err)
	}
	xlFile, err := xlsx.OpenBinary(fileByte)
	if err != nil {
		fmt.Printf("open failed: %s\n", err)
	}
	batchUpdateTitles := []string{"团队编号", "用户ID", "密码", "手机号", "姓名", "登录权限（0：注销；1：正常；2：封禁）", "项目领取限制（项目ID，领取上限，领取下限）", "权限变更类型（1：新增权限；2：删除权限；3：覆盖权限）"}
	var userServe services.UserService
	var res ImportsResponse
	for _, sheet := range xlFile.Sheets {
		for i, row := range sheet.Rows {
			var errListLength = len(res.ErrList)
			//判断excel格式对不对
			if i == 0 {
				for j, cell := range row.Cells {
					if strings.TrimSpace(cell.String()) != batchUpdateTitles[j] {
						ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: fmt.Sprintf("文件表头格式不对,%s", cell.String())})
						return
					}
				}
			}
			//从第三行开始
			if i >= 2 {
				res.TotalRows += 1
				var rowsList []string
				var userObj dao.SystemUser
				var row_data string
				for j, cell := range row.Cells {
					text := strings.TrimSpace(cell.String())
					row_data += text
					if text == "" && j < len(batchUpdateTitles) {
						res.ErrList = append(res.ErrList, code.ImportError{
							Sheet:  sheet.Name,
							Number: i + 1,
							Cell:   j + 1,
							Reason: fmt.Sprintf("第%d行字段%s的值不能为空", i+1, batchUpdateTitles[j]),
						})
					}
					rowsList = append(rowsList, text)
				}

				if strings.TrimSpace(row_data) == "" {
					res.TotalRows -= 1
					break
				}
				if len(rowsList) < len(batchUpdateTitles) {
					for k := len(rowsList); k < len(batchUpdateTitles); k++ {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   k + 1,
							Reason: fmt.Sprintf("第%d行字段%s的值不能为空", i+1, batchUpdateTitles[k]),
						})
					}
					res.FailRows += 1
					continue
				}

				userObj.TeamNumber = rowsList[0]
				userObj.UserId = rowsList[1]
				userObj.PassWord = utils.Base64Encode(rowsList[2])
				userObj.Phone = rowsList[3]
				userObj.RealName = rowsList[4]
				if rowsList[5] != "" {
					userObj.Status, err = strconv.Atoi(rowsList[5])
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   5 + 1,
							Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, batchUpdateTitles[5]),
						})
					}
					if arrays.Contains([]int{0, 1, 2}, userObj.Status) == -1 {
						res.ErrList = append(res.ErrList, code.ImportError{
							Sheet:  sheet.Name,
							Number: i + 1,
							Cell:   5 + 1,
							Reason: fmt.Sprintf("第%d行字段%s的值非有效值", i+1, batchUpdateTitles[5]),
						})
					}
				}
				if rowsList[6] != "" {
					for _, item := range strings.Split(rowsList[6], "；") {
						if strings.TrimSpace(item) == "" {
							continue
						}
						items := strings.Split(item, "，")
						if len(items) != 3 {
							res.ErrList = append(res.ErrList, code.ImportError{
								Sheet:  sheet.Name,
								Number: i + 1,
								Cell:   6 + 1,
								Reason: fmt.Sprintf("第%d行-%d列数据格式不对", i+1, 7),
							})
							continue
						}
						lowerLimit, err := strconv.Atoi(strings.TrimSpace(items[2]))
						if err != nil {
							res.ErrList = append(res.ErrList, code.ImportError{
								Sheet:  sheet.Name,
								Number: i + 1,
								Cell:   6 + 1,
								Reason: fmt.Sprintf("第%d行-%d列数据格式不对", i+1, 7),
							})
						}
						limit, err := strconv.Atoi(strings.TrimSpace(items[1]))
						if err != nil {
							res.ErrList = append(res.ErrList, code.ImportError{
								Sheet:  sheet.Name,
								Number: i + 1,
								Cell:   6 + 1,
								Reason: fmt.Sprintf("第%d行-%d列数据格式不对", i+1, 7),
							})
						}
						if lowerLimit > limit {
							res.ErrList = append(res.ErrList, code.ImportError{
								Sheet:  sheet.Name,
								Number: i + 1,
								Cell:   6 + 1,
								Reason: fmt.Sprintf("第%d行-%d最低下限不能超过最高上限", i+1, 7),
							})
						}
						userObj.SystemUserRestriction = append(userObj.SystemUserRestriction, modelbase.SystemUserRestriction{
							ProjectId:  strings.TrimSpace(items[0]),
							LowerLimit: lowerLimit,
							Limit:      limit,
						})
					}
				}

				var mouthed int
				if rowsList[7] != "" {
					mouthed, err = strconv.Atoi(rowsList[7])
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   7 + 1,
							Reason: fmt.Sprintf("第%d字段%s的数据格式不对", i+1, batchUpdateTitles[7]),
						})
					}
					if arrays.Contains([]int{3, 1, 2}, mouthed) == -1 {
						res.ErrList = append(res.ErrList, code.ImportError{
							Sheet:  sheet.Name,
							Number: i + 1,
							Cell:   7 + 1,
							Reason: fmt.Sprintf("第%d行字段%s的值非有效值", i+1, batchUpdateTitles[7]),
						})
					}
				}
				if len(res.ErrList) > errListLength {
					res.FailRows += 1
					continue
				}

				if err := userServe.ExcelBatchUpdate(map[string]interface{}{"user_id": rowsList[1]}, userObj, mouthed); err != nil {
					switch mysqlhandler.MysqlErrCode(err) {
					case mysqlhandler.ErrDuplicateEntryCode:
						res.ErrList = append(res.ErrList, code.ImportError{
							Sheet:  sheet.Name,
							Number: i + 1,
							Reason: "该条数据已经存在，请检查用户Id或手机号码是否已经存在系统中！"})
					default:
						res.ErrList = append(res.ErrList, code.ImportError{
							Sheet:  sheet.Name,
							Number: i + 1,
							Reason: err.Error()})
					}
					res.FailRows += 1
					continue
				}
			}
		}
	}
	res.SuccessRows = res.TotalRows - res.FailRows
	ctx.JSON(utils.Response{
		Code:    200,
		Message: "ok",
		Data:    res,
	})
	return
}

type UserListRequest struct {
	Page                 int64  `json:"page"`
	PageSize             int64  `json:"page_size"`
	UserId               string `json:"user_id"`                 //用户ID
	RealName             string `json:"real_name"`               //姓名
	NickName             string `json:"nick_name"`               //昵称
	TeamNumber           string `json:"team_number"`             //团队编号
	Phone                string `json:"phone"`                   //手机号
	Email                string `json:"email"`                   //邮箱
	IsAuthentication     string `json:"is_authentication"`       //实名状态(0 未认证;1 已认证)
	Status               string `json:"status"`                  //状态(0 注销;1 正常; 2 封禁)
	Auth                 string `json:"auth"`                    //权限
	Balance              string `json:"balance"`                 //当前芝草
	ThisMonthUsedBalance string `json:"this_month_used_balance"` //本月兑换芝草
	HistoryBalance       string `json:"history_balance"`         //历史芝草
	RegisterTimeStart    string `json:"register_time_start"`     //注册时间起
	RegisterTimeEnd      string `json:"register_time_end"`       //注册时间止
	LastLoginTimeStart   string `json:"last_login_time_start"`   //最后一次登录时间起
	LastLoginTimeEnd     string `json:"last_login_time_end"`     //最后一次登录时间止
}

// @Summary 用户列表
// @Description 用户列表
// @Tags 用户
// @Accept application/json
// @Produce application/json
// @param Accept-Version header string true "1.0.0"
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param param body UserListRequest true "用户列表接口参数"
// @Success 200 {object} utils.Response --> 成功后返回数据结构
// @Failure 400 {object} utils.ResponseError --> 失败后返回数据结构
// @Router /admin/user/list [post]
func UserListHandler(ctx iris.Context) {
	var RequestParams UserListRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var userServe services.UserService

	//判断权限
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	wherestr := []string{}
	/*if claims.Type == 2 {

		var admin dao.Common[dao.SystemAdmin]
		admin.Query = map[string]interface{}{"id": claims.Id}
		systemAdmin, err := admin.First(admin.Query)
		if err != nil {
			ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
			return
		}
		wherestr = append(wherestr, fmt.Sprintf("team_number IN ('%s')", strings.Join(systemAdmin.TeamPermissions, "','")))
	}*/
	if utils.StringIsNotEmpty(RequestParams.UserId) {
		wherestr = append(wherestr, fmt.Sprintf("user_id like '%%%v%%'", RequestParams.UserId))
	}
	if utils.StringIsNotEmpty(RequestParams.RealName) {
		wherestr = append(wherestr, fmt.Sprintf("real_name like '%%%v%%'", RequestParams.RealName))
	}
	if utils.StringIsNotEmpty(RequestParams.NickName) {
		wherestr = append(wherestr, fmt.Sprintf("nick_name like '%%%v%%'", RequestParams.NickName))
	}
	if utils.StringIsNotEmpty(RequestParams.TeamNumber) {
		wherestr = append(wherestr, fmt.Sprintf("team_number like '%%%v%%'", RequestParams.TeamNumber))
	}
	if utils.StringIsNotEmpty(RequestParams.Phone) {
		wherestr = append(wherestr, fmt.Sprintf("phone like '%%%v%%'", RequestParams.Phone))
	}
	if utils.StringIsNotEmpty(RequestParams.Email) {
		wherestr = append(wherestr, fmt.Sprintf("email like '%%%v%%'", RequestParams.Email))
	}
	if utils.StringIsNotEmpty(RequestParams.IsAuthentication) {
		wherestr = append(wherestr, fmt.Sprintf("is_authentication = %v ", RequestParams.IsAuthentication))
	}
	if utils.StringIsNotEmpty(RequestParams.Status) {
		wherestr = append(wherestr, fmt.Sprintf("status = %v", RequestParams.Status))
	}
	if utils.StringIsNotEmpty(RequestParams.Auth) {
		wherestr = append(wherestr, fmt.Sprintf("id in (SELECT DISTINCT(system_user_id) from tas_system_user_restriction WHERE project_id = '%v') ", RequestParams.Auth))
	}
	if utils.StringIsNotEmpty(RequestParams.Balance) {
		wherestr = append(wherestr, fmt.Sprintf("balance = %v", RequestParams.Balance))
	}
	if utils.StringIsNotEmpty(RequestParams.RegisterTimeStart) && utils.StringIsNotEmpty(RequestParams.RegisterTimeEnd) {
		wherestr = append(wherestr, fmt.Sprintf("created_at >= '%v' and created_at <= '%v'", RequestParams.RegisterTimeStart, RequestParams.RegisterTimeEnd))
	}
	if utils.StringIsNotEmpty(RequestParams.LastLoginTimeStart) && utils.StringIsNotEmpty(RequestParams.LastLoginTimeEnd) {
		wherestr = append(wherestr, fmt.Sprintf("last_login_time >= '%v' and last_login_time <= '%v'", RequestParams.LastLoginTimeStart, RequestParams.LastLoginTimeEnd))
	}
	if res, err := userServe.GetUserList(RequestParams.Page, RequestParams.PageSize, wherestr); err != nil {
		ctx.JSON(utils.ResponseError{
			Code:    iris.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	} else {
		ctx.JSON(utils.Response{
			Code:    200,
			Message: "ok",
			Data:    iris.Map{"count": res.Total, "list": res.Data},
		})
		return
	}
}

type UserTopicQuantityRequest struct {
	RealName        string   `json:"real_name"`
	Status          int      `json:"status"`
	UserId          string   `json:"user_id"`
	TeamNumber      string   `json:"u_team_number"`
	UserGetDateTime []string `json:"user_get_date_time"`
	Page            int64    `json:"page"`
	PageSize        int64    `json:"page_size"`
}

// @Summary 用户题量
// @Description 用户题量
// @Tags 用户
// @Accept application/json
// @Produce application/json
// @param Accept-Version header string true "1.0.0"
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param param body UserTopicQuantityRequest true "用户题量参数"
// @Success 200 {object} utils.Response --> 成功后返回数据结构
// @Failure 400 {object} utils.ResponseError --> 失败后返回数据结构
// @Router /admin/user/topic_quantity [post]
func UserTopicQuantityHandler(ctx iris.Context) {
	var RequestParams UserTopicQuantityRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	type SystemTopic struct {
		Id            uint      `json:"id"`
		SN            int       `json:"sn"`                                               //序号
		ProjectId     string    `json:"project_id" gorm:"index:project_topic_idx,unique"` //关联的项目Id
		TopicId       string    `json:"topic_id" gorm:"index:project_topic_idx,unique"`   //自定义题目Id
		Title         string    `json:"title"`                                            //题目标题
		Status        int       `json:"status"`                                           //状态 0未生效 1已完成 2已领取 3指派中 4返修中 5闲置中 6已作废
		EffectiveTime time.Time `json:"effective_time"`                                   //题目生效时间
		EndDateTime   time.Time `json:"end_date_time"`                                    //截止时间
		FinishTime    time.Time `json:"finish_time"`                                      //完成时间
		HaveRead      int       `json:"have_read"`                                        //当状态为返修的时候，此字段 0 未读 1已读
		ReceiverId    string    `json:"receiver_id"`                                      //领取人的Id
		RealName      string    `json:"real_name"`
		UserId        string    `json:"user_id"`
		UTeamNumber   string    `json:"u_team_number"`
		Phone         string    `json:"phone"`
		GetDateTime   time.Time `json:"get_date_time"`
	}
	var topic_user_Serve services.CommonService[SystemTopic]
	topic_user_Serve.Query = map[string]interface{}{}
	if RequestParams.Status != -1 {
		//topic_user_Serve.Query["tas_topic_user_record.status"] = RequestParams.Status
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("tas_system_topic.status = %d", RequestParams.Status))
	}
	topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("tas_system_topic.receiver_id != \"\""))
	if RequestParams.UserId != "" {
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("receiver_id LIKE '%%%v%%'", RequestParams.UserId))
	}
	if RequestParams.RealName != "" {
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("u.real_name LIKE '%%%v%%'", RequestParams.RealName))
	}

	if RequestParams.TeamNumber != "" {
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("u.team_number LIKE '%%%v%%'", RequestParams.TeamNumber))
	}

	if len(RequestParams.UserGetDateTime) > 0 {
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("r.created_at BETWEEN '%s' AND '%s'", RequestParams.UserGetDateTime[0], RequestParams.UserGetDateTime[1]))
	}

	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var admin dao.Common[dao.SystemAdmin]
	systemAdmin, _ := admin.First(map[string]interface{}{"id": claims.Id})
	if systemAdmin.AdminType == 2 {

		var project_permissions []string
		for _, project_id := range systemAdmin.ProjectPermissions {
			project_permissions = append(project_permissions, project_id)
		}
		var team_numbers []string
		for _, team := range systemAdmin.TeamPermissions {
			team_numbers = append(team_numbers, team)
		}
		if len(project_permissions) > 0 {
			topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("tas_system_topic.project_id IN ('%s') AND u.team_number IN ('%s')", strings.Join(project_permissions, "','"), strings.Join(team_numbers, "','")))
		}
	}

	field := fmt.Sprintf("tas_system_topic.*,u.real_name,u.user_id,u.team_number as u_team_number,u.phone,r.get_date_time as get_date_time")
	topic_user_Serve.SelectField = &field
	recordsql := "SELECT ANY_VALUE(user_id) as user_id,system_topic_id,MAX(DISTINCT tas_topic_user_record.created_at) AS get_date_time FROM tas_topic_user_record WHERE tas_topic_user_record.tp = 1 GROUP BY tas_topic_user_record.system_topic_id,user_id"
	topic_user_Serve.LeftJoin = append(topic_user_Serve.LeftJoin, fmt.Sprintf("left join tas_system_user as u on u.user_id = tas_system_topic.receiver_id"))
	topic_user_Serve.LeftJoin = append(topic_user_Serve.LeftJoin, fmt.Sprintf("left join (%s) as r on tas_system_topic.receiver_id = r.user_id and r.system_topic_id= tas_system_topic.id", recordsql))
	topic_user_Serve.Page = RequestParams.Page
	topic_user_Serve.PageSize = RequestParams.PageSize
	topic_user_Serve.Distinct = "tas_system_topic.id"
	//topic_user_Serve.Order = "r.created_at DESC"
	if res, err := topic_user_Serve.SelectList(); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	} else {
		ctx.JSON(utils.Response{Code: iris.StatusOK, Message: iris.StatusText(iris.StatusOK), Data: iris.Map{"count": res.Total, "list": res.Data}})
		return
	}
}

//用户题量全部导出

func UserTopicQuantityExportHandler(ctx iris.Context) {
	var RequestParams UserTopicQuantityRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var service services.CommonService[dao.SystemProject]
	service.Query = map[string]interface{}{}

	type SystemTopic struct {
		Id uint `json:"id"`
	}
	var topic_user_Serve services.CommonService[SystemTopic]
	topic_user_Serve.Query = map[string]interface{}{}
	if RequestParams.Status != -1 {
		//topic_user_Serve.Query["tas_topic_user_record.status"] = RequestParams.Status
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("tas_system_topic.status = %d", RequestParams.Status))
	}
	topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("tas_system_topic.receiver_id != \"\""))
	if RequestParams.UserId != "" {
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("receiver_id LIKE '%%%v%%'", RequestParams.UserId))
	}
	if RequestParams.RealName != "" {
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("u.real_name LIKE '%%%v%%'", RequestParams.RealName))
	}

	if RequestParams.TeamNumber != "" {
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("u.team_number LIKE '%%%v%%'", RequestParams.TeamNumber))
	}

	if len(RequestParams.UserGetDateTime) > 0 {
		topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("r.created_at BETWEEN '%s' AND '%s'", RequestParams.UserGetDateTime[0], RequestParams.UserGetDateTime[1]))
	}

	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var admin dao.Common[dao.SystemAdmin]
	systemAdmin, _ := admin.First(map[string]interface{}{"id": claims.Id})
	if systemAdmin.AdminType == 2 {

		var project_permissions []string
		for _, project_id := range systemAdmin.ProjectPermissions {
			project_permissions = append(project_permissions, project_id)
		}
		var team_numbers []string
		for _, team := range systemAdmin.TeamPermissions {
			team_numbers = append(team_numbers, team)
		}
		if len(project_permissions) > 0 {
			topic_user_Serve.WhereStr = append(topic_user_Serve.WhereStr, fmt.Sprintf("tas_system_topic.project_id IN ('%s') AND u.team_number IN ('%s')", strings.Join(project_permissions, "','"), strings.Join(team_numbers, "','")))
		}
	}

	field := fmt.Sprintf("tas_system_topic.Id")
	topic_user_Serve.SelectField = &field
	recordsql := "SELECT ANY_VALUE(user_id) as user_id,system_topic_id,MAX(DISTINCT tas_topic_user_record.created_at) AS get_date_time FROM tas_topic_user_record WHERE tas_topic_user_record.tp = 1 GROUP BY tas_topic_user_record.system_topic_id,user_id"
	topic_user_Serve.LeftJoin = append(topic_user_Serve.LeftJoin, fmt.Sprintf("left join tas_system_user as u on u.user_id = tas_system_topic.receiver_id"))
	topic_user_Serve.LeftJoin = append(topic_user_Serve.LeftJoin, fmt.Sprintf("left join (%s) as r on tas_system_topic.receiver_id = r.user_id and r.system_topic_id= tas_system_topic.id", recordsql))
	topic_user_Serve.Distinct = "tas_system_topic.id"
	findAll, _ := topic_user_Serve.FindWithLeftJoinAll()
	var topics []uint
	topics = append(topics, 0)
	for _, topic := range findAll {
		topics = append(topics, topic.Id)
	}
	var topicAnswerServer services.TopicAnswerService
	ExportData, err := topicAnswerServer.ExportAnswer(topics, []string{})
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	exportFile := excelize.NewFile()
	style, _ := exportFile.NewStyle(&excelize.Style{
		Fill: excelize.Fill{Type: "gradient", Color: []string{"#8ED3F5", "#8ED3F5"}, Shading: 1},
	})
	style1, _ := exportFile.NewStyle(&excelize.Style{
		Fill: excelize.Fill{Type: "gradient", Color: []string{"#F1B735", "#F1B735"}, Shading: 1},
	})
	//创建工作表行数
	var excel = make(map[string][]interface{}, 0)
	//比较表头的长度
	var excelHeader = make(map[string]int, 0)
	titles := []string{"项目ID", "发题日期", "题目序号", "题目ID", "题目名称", "本题开放回答的时间", "截止时间", "完成时间", "填写领取老师姓名", "放弃原因"}
	//删除默认工作表
	for _, datum := range ExportData {
		sheetsTitle := titles
		//处理表头
		colNameDefault := generateColName(10)
		var rowsData []interface{}
		rowsData = append(rowsData, datum.ProjectId)
		rowsData = append(rowsData, datum.PushTopicDate.Format(timehandler.FormatLayoutDate))
		rowsData = append(rowsData, datum.SN)
		rowsData = append(rowsData, datum.TopicId)
		rowsData = append(rowsData, datum.TopicTitle)
		rowsData = append(rowsData, datum.EffectiveTime.Format(timehandler.FormatLayoutTime))
		rowsData = append(rowsData, datum.EndDateTime.Format(timehandler.FormatLayoutTime))
		rowsData = append(rowsData, datum.ReceiveTime.Format(timehandler.FormatLayoutTime))
		rowsData = append(rowsData, datum.RealName)
		rowsData = append(rowsData, datum.GiveUpReason)
		sheet := fmt.Sprintf("%s_%s", datum.ProjectId, datum.BatchId)
		excel[sheet] = append(excel[sheet], rowsData)
		exportFile.NewSheet(sheet)
		startName := generateColName(len(titles) + 1)

		//处理题目配置和答案
		var answerList []interface{}
		//类型 、选填 、标题、内容
		stringsDeduplicate := arrays.StringsDeduplicate(strings.Split(datum.Answers, "[@@]"))
		for i, a := range stringsDeduplicate {
			splitAnswer := strings.Split(a, "[#]")
			if len(splitAnswer) < 4 {
				continue
			}
			title := fmt.Sprintf("提交内容-%d：", i+1)
			if splitAnswer[0] == "1" {
				currentColName := generateColName(len(titles) + len(answerList) + 1)
				exportFile.SetCellHyperLink(sheet, fmt.Sprintf("%s%d", currentColName, len(excel[sheet])+1), splitAnswer[3], "External")
				title += "文件上传"
			} else {
				title += "在线文本"
			}
			if splitAnswer[1] == "0" {
				title += "（必填）"
			} else {
				title += "（选填）"
			}
			title += "-" + splitAnswer[2]
			sheetsTitle = append(sheetsTitle, title)
			answerList = append(answerList, splitAnswer[3])

		}
		endName := generateColName(len(titles) + len(answerList))

		rowsData = append(rowsData, answerList...)
		if len(sheetsTitle)-len(rowsData) > 0 {
			var NullSlice = make([]interface{}, len(sheetsTitle)-len(rowsData))
			rowsData = append(rowsData, NullSlice...)
		}
		//计算备注的长度
		var noteList []interface{}
		for i, s := range strings.Split(datum.Note, "[@@]") {
			splitHeader := strings.Split(s, "[#]")
			sheetsTitle = append(sheetsTitle, fmt.Sprintf("备注%d", i+1))
			noteList = append(noteList, splitHeader[1])
		}
		rowsData = append(rowsData, noteList...)

		exportFile.SetCellStyle(sheet, "A1", colNameDefault+"1", style)
		exportFile.SetCellStyle(sheet, startName+"1", endName+"1", style1)
		//插入表头
		if _, ok := excelHeader[sheet]; ok {
			if excelHeader[sheet] < len(sheetsTitle) {
				exportFile.SetSheetRow(sheet, "A1", &sheetsTitle)
				excelHeader[sheet] = len(sheetsTitle)
			}
		} else {
			exportFile.SetSheetRow(sheet, "A1", &sheetsTitle)
			excelHeader[sheet] = len(sheetsTitle)
		}
		//插入内容
		exportFile.SetSheetRow(sheet, fmt.Sprintf("A+%d", len(excel[sheet])+1), &rowsData)
	}
	exportFile.DeleteSheet("Sheet1")
	unix := time.Now().UnixNano()
	tempFilename := fmt.Sprintf("./export/topic_answer_%d.xlsx", unix)
	if err := exportFile.SaveAs(tempFilename); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}

	defer exportFile.Close()
	//删除本地临时文件
	defer os.Remove(tempFilename)
	bucketClient := oss.BucketClient{}
	readFile, _ := ioutil.ReadFile(fmt.Sprintf("./export/topic_answer_%d.xlsx", unix))
	bucketClient.UpBytes(readFile, fmt.Sprintf("task-assign/answer/export/topic_answer_%d.xlsx", unix))
	ctx.JSON(utils.Response{Code: iris.StatusOK, Message: iris.StatusText(iris.StatusOK), Data: fmt.Sprintf("%s/task-assign/answer/export/topic_answer_%d.xlsx", utils.ServerConf.AliOssConf.CallBackHost, unix)})
	return
}

type UserProjectAnalysisRequest struct {
	Page             int      `json:"page"`
	PageSize         int      `json:"page_size"`
	RealName         string   `json:"real_name"`
	UploadRate       float64  `json:"upload_rate"`
	TeamNumber       string   `json:"team_number"`
	RegistrationDate []string `json:"registration_date"`
	Submit           []uint   `json:"submit"`
	Get              []uint   `json:"get"`
}

// @Summary 用户项目分析
// @Description 用户项目分析
// @Tags 用户
// @Accept application/json
// @Produce application/json
// @param Accept-Version header string true "1.0.0"
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param param body UserProjectAnalysisRequest true "用户项目分析参数"
// @Success 200 {object} utils.Response --> 成功后返回数据结构
// @Failure 400 {object} utils.ResponseError --> 失败后返回数据结构
// @Router /admin/user/project_analysis [post]
func UserProjectAnalysisHandler(ctx iris.Context) {
	var RequestParams UserProjectAnalysisRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var userRecordServe services.TopicUserRecordService
	wheres := []string{}
	if RequestParams.RealName != "" {
		wheres = append(wheres, fmt.Sprintf("real_name LIKE '%%%v%%'", RequestParams.RealName))
	}
	if RequestParams.TeamNumber != "" {
		wheres = append(wheres, fmt.Sprintf("team_number LIKE '%%%v%%'", RequestParams.TeamNumber))
	}
	if RequestParams.UploadRate != 0 {
		wheres = append(wheres, fmt.Sprintf("TRUNCATE(us.submit*100/us.get, 2) >= %v", RequestParams.UploadRate))
	}

	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var admin dao.Common[dao.SystemAdmin]
	systemAdmin, _ := admin.First(map[string]interface{}{"id": claims.Id})
	if systemAdmin.AdminType == 2 {

		var project_permissions []string
		for _, project_id := range systemAdmin.ProjectPermissions {
			project_permissions = append(project_permissions, project_id)
		}
		var team_numbers []string
		for _, team := range systemAdmin.TeamPermissions {
			team_numbers = append(team_numbers, team)
		}
		if len(project_permissions) > 0 {
			wheres = append(wheres, fmt.Sprintf("us.project_id IN ('%s') AND tas_system_user.team_number IN ('%s')", strings.Join(project_permissions, "','"), strings.Join(team_numbers, "','")))
		}
	}

	if len(RequestParams.Submit) > 0 {
		wheres = append(wheres, fmt.Sprintf("us.submit BETWEEN %d AND %d", RequestParams.Submit[0], RequestParams.Submit[1]))
	}
	if len(RequestParams.Get) > 0 {
		wheres = append(wheres, fmt.Sprintf("us.get BETWEEN %d AND %d", RequestParams.Get[0], RequestParams.Get[1]))
	}
	if len(RequestParams.RegistrationDate) > 0 {
		wheres = append(wheres, fmt.Sprintf("tas_system_user.created_at BETWEEN '%s' AND '%s'", RequestParams.RegistrationDate[0], RequestParams.RegistrationDate[1]))
	}
	analysis, _ := userRecordServe.UserProjectAnalysis(RequestParams.Page, RequestParams.PageSize, wheres)
	ctx.JSON(utils.Response{Code: iris.StatusOK, Message: iris.StatusText(iris.StatusOK), Data: analysis})
	return
}

type UserProjectAnalysisExportRequest struct {
	RealName         string   `json:"real_name"`
	UploadRate       float64  `json:"upload_rate"`
	TeamNumber       string   `json:"team_number"`
	RegistrationDate []string `json:"registration_date"`
	Submit           []uint   `json:"submit"`
	Get              []uint   `json:"get"`
	UserProjectIds   []string `json:"user_project_ids"`
}

// @Summary 用户项目分析导出
// @Description 用户项目分析导出
// @Tags 用户
// @Accept application/json
// @Produce application/json
// @param Accept-Version header string true "1.0.0"
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param param body UserProjectAnalysisExportRequest true "用户项目分析导出参数"
// @Success 200 {object} utils.Response --> 成功后返回数据结构
// @Failure 400 {object} utils.ResponseError --> 失败后返回数据结构
// @Router /admin/user/project_analysis/export [post]
func ExportUserProjectAnalysisHandler(ctx iris.Context) {
	var RequestParams UserProjectAnalysisExportRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}
	var userRecordServe services.TopicUserRecordService
	var wheres []string
	if RequestParams.RealName != "" {
		wheres = append(wheres, fmt.Sprintf("real_name LIKE '%%%v%%'", RequestParams.RealName))
	}
	if RequestParams.TeamNumber != "" {
		wheres = append(wheres, fmt.Sprintf("team_number LIKE '%%%v%%'", RequestParams.TeamNumber))
	}
	if RequestParams.UploadRate != 0 {
		wheres = append(wheres, fmt.Sprintf("TRUNCATE(us.submit*100/us.get, 2) >= %v", RequestParams.UploadRate))
	}
	if len(RequestParams.Submit) > 0 {
		wheres = append(wheres, fmt.Sprintf("us.submit BETWEEN %d AND %d", RequestParams.Submit[0], RequestParams.Submit[1]))
	}
	if len(RequestParams.Get) > 0 {
		wheres = append(wheres, fmt.Sprintf("us.get BETWEEN %d AND %d", RequestParams.Get[0], RequestParams.Get[1]))
	}
	if len(RequestParams.RegistrationDate) > 0 {
		wheres = append(wheres, fmt.Sprintf("tas_system_user.created_at BETWEEN '%s' AND '%s'", RequestParams.RegistrationDate[0], RequestParams.RegistrationDate[1]))
	}
	if len(RequestParams.UserProjectIds) > 0 {

		wheres = append(wheres, fmt.Sprintf("CONCAT(us.user_id,'@',us.project_id) IN ('%s')", strings.Join(RequestParams.UserProjectIds, "','")))
	}
	analysis, _ := userRecordServe.UserProjectAnalysis(0, 0, wheres)
	exportFile := excelize.NewFile()
	style, _ := exportFile.NewStyle(&excelize.Style{
		Fill: excelize.Fill{Type: "gradient", Color: []string{"#F1B735", "#F1B735"}, Shading: 1},
	})

	exportFile.InsertRow("Sheet1", len(analysis.List)+1)
	titles := []string{"团队编号", "账号ID", "姓名", "注册时间", "手机号", "项目ID", "累计领取", "累计上传", "累计放弃", "上传率"}
	var colName string
	dividend := len(titles)
	var modulo int
	for dividend > 0 {
		modulo = (dividend - 1) % 26
		// Convert int to string
		colName = string(65+modulo) + colName
		dividend = (int)((dividend - modulo) / 26)
	}

	exportFile.SetCellStyle("Sheet1", "A1", colName+"1", style)
	exportFile.SetSheetRow("Sheet1", "A1", &titles)
	for i, datum := range analysis.List {
		var rowsData []interface{}
		rowsData = append(rowsData, datum.TeamNumber)
		rowsData = append(rowsData, datum.UserId)
		rowsData = append(rowsData, datum.RealName)
		rowsData = append(rowsData, datum.JoinDate.Format(utils.ServerConf.TimeLayoutStr))
		rowsData = append(rowsData, datum.Phone)
		rowsData = append(rowsData, datum.ProjectId)
		rowsData = append(rowsData, datum.Get)
		rowsData = append(rowsData, datum.Submit)
		rowsData = append(rowsData, datum.GiveUp)
		rowsData = append(rowsData, strconv.FormatFloat(datum.Sg, 'f', 2, 64)+"%")
		exportFile.SetSheetRow("Sheet1", fmt.Sprintf("A+%d", i+2), &rowsData)
	}
	unix := time.Now().UnixNano()
	tempFilename := fmt.Sprintf("./export/user_project_%d.xlsx", unix)
	if err := exportFile.SaveAs(tempFilename); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	defer exportFile.Close()
	defer os.Remove(tempFilename)
	bucketClient := oss.BucketClient{}
	readFile, _ := ioutil.ReadFile(fmt.Sprintf("./export/user_project_%d.xlsx", unix))
	if err := bucketClient.UpBytes(readFile, fmt.Sprintf("task-assign/export/user_project_%d.xlsx", unix)); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	} else {
		ctx.JSON(utils.Response{Code: iris.StatusOK, Message: iris.StatusText(iris.StatusOK), Data: fmt.Sprintf("%s/task-assign/export/user_project_%d.xlsx", utils.ServerConf.AliOssConf.CallBackHost, unix)})
		return

	}
}

func UserBalanceStatisticsHandler(ctx iris.Context) {
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var userServe services.UserService
	if res, err := userServe.UserBalanceStatistics(claims.Id); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseData(res))
		return
	}
}

func UserBalanceIncomesHandler(ctx iris.Context) {
	var RequestParams BaseRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var serve services.UserBalanceLogService
	if total, list, err := serve.UserBalanceIncomes(claims.Id, RequestParams.Page, RequestParams.PageSize); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseData(iris.Map{"count": total, "list": list}))
		return
	}
}

type IncomeRankRequest struct {
	Type      string `json:"type"`       //查询类型，1：日榜，2：周榜，3：月榜，不传查全部
	StartDate string `json:"start_date"` //开始日期
	EndDate   string `json:"end_date"`   //结束日期
}

func UserIncomeRankHandler(ctx iris.Context) {
	var RequestParams IncomeRankRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var serve services.UserBalanceLogService
	if from, to, list, userRank, err := serve.UserIncomeRank(RequestParams.Type, claims.Id); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseData(iris.Map{"from": from, "to": to, "count": len(list), "list": list, "userRank": userRank}))
		return
	}
}

func TeamIncomeRankHandler(ctx iris.Context) {
	var RequestParams IncomeRankRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var serve services.UserBalanceLogService
	if from, to, list, err := serve.TeamIncomeRank(RequestParams.Type); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		type TeamIncomeRankResponse struct {
			Number       string `json:"number"`         //排名
			TeamNumber   string `json:"team_number"`    //团队编号
			Des          string `json:"des"`            //说明
			Avatar       string `json:"avatar"`         //头像
			TeamNickName string `json:"team_nick_name"` //团长昵称
		}
		var tl TeamIncomeRankResponse
		var userDao dao.Common[dao.SystemUser]
		if user, err := userDao.First(map[string]interface{}{"id": claims.Id}); err == nil {
			var teamDao dao.Common[dao.SystemTeam]
			if userTeam, err := teamDao.First(map[string]interface{}{"user_id": user.UserId}); err == nil {
				if !utils.StringIsEmpty(userTeam.TeamNumber) {
					for _, team := range list {
						if userTeam.TeamNumber == team.TeamNumber {
							tl = TeamIncomeRankResponse(team)
						}
					}
				}
			}
		}
		if len(list) >= 50 {
			list = list[:50]
		}
		ctx.JSON(utils.ResponseData(iris.Map{"from": from, "to": to, "count": len(list), "list": list, "teamRank": tl}))
		return
	}
}

type UserBalanceDetailRequest struct {
	UserId string `json:"user_id" validate:"required"`
}

func QueryUserBalanceDetailHandler(ctx iris.Context) {
	var RequestParams UserBalanceDetailRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}
	var serve services.UserBalanceLogService
	if res, err := serve.QueryUserBalanceDetail(RequestParams.UserId); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseData(res))
		return
	}
}

func RefreshUserIncomeRankHandler(ctx iris.Context) {
	ctx.JSON(utils.ResponseOK())
	return
}

type BatchDelUserRequest struct {
	Ids []uint `json:"ids"` //用户id
}

func BatchDelUserHandler(ctx iris.Context) {
	var RequestParams BatchDelUserRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var userServe services.UserService
	if err := userServe.BatchDelUser(RequestParams.Ids); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseOK())
		return
	}
}

type UploadDelUser struct {
	UserId string `excel:"用户ID(必填)"`
}

func (*UploadDelUser) Configure(rc *exl.ReadConfig) {}

func UploadDelUserHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	if models, err := exl.Read[*UploadDelUser](file); err != nil {
		fmt.Println("read excel err:" + err.Error())
		ctx.JSON(utils.ResponseServerError(errors.New("excel读取错误")))
		return
	} else {
		fmt.Printf("read excel num: %d\n", len(models))
		var userObjs []*dao.SystemUser
		index := 0
		for i, model := range models {
			//从第二行开始读取
			if i == 0 {
				continue
			}
			var userObj dao.SystemUser
			userObj.UserId = model.UserId
			userObjs = append(userObjs, &userObj)
			index++
		}
		var userServe services.UserService
		if err := userServe.BatchImportDelUser(userObjs); err != nil {
			ctx.JSON(utils.ResponseServerError(err))
			return
		}
		ctx.JSON(utils.ResponseOK())
		return
	}
}

type ExportUser struct {
	UserId           string `excel:"用户ID"`                                                     //用户Id
	TeamNumber       string `excel:"团队编号"`                                                     //团队编号
	UserNumber       string `excel:"编号"`                                                       //编号
	NickName         string `excel:"昵称"`                                                       //昵称
	RealName         string `excel:"姓名"`                                                       //姓名
	IsAuthentication int    `excel:"实名状态"`                                                     //是否实名认证，0 未认证;1 已认证;
	Phone            string `excel:"手机号"`                                                      //手机号
	Email            string `excel:"邮箱"`                                                       //邮箱
	PassWord         string `excel:"密码"`                                                       //密码
	AlipayAccount    string `excel:"支付宝"`                                                      //支付宝账号
	DeliveryAddress  string `excel:"地址"`                                                       //收货地址
	Introduction     string `excel:"个人简介"`                                                     //简介
	IdCardNumber     string `excel:"身份证号码"`                                                    //身份证号码
	IdCardFace       string `excel:"身份证头像面"`                                                   //身份证头像照
	IdCardBack       string `excel:"身份证国徽面"`                                                   //身份证国徽照
	Balance          string `excel:"我的芝草（100；100；1000；10000）（当前芝草；本月已兑换芝草，历史累计支出芝草；历史累计获得芝草）"` //用户芝草余额
	Avatar           string `excel:"头像"`                                                       //用户头像
	Status           int    `excel:"状态"`                                                       //0 注销;1 正常; 2 封禁
	CreatedAt        string `excel:"注册时间"`
	LastLoginTime    string `excel:"最后一次登录时间"` //最后一次登录时间
	UserRestriction  string `excel:"领取限制"`     //项目领取限制
}
type ExportUserRequest struct {
	Ids                  []uint `json:"ids"`
	UserId               string `json:"user_id"`                 //用户ID
	RealName             string `json:"real_name"`               //姓名
	NickName             string `json:"nick_name"`               //昵称
	TeamNumber           string `json:"team_number"`             //团队编号
	Phone                string `json:"phone"`                   //手机号
	Email                string `json:"email"`                   //邮箱
	IsAuthentication     string `json:"is_authentication"`       //实名状态(0 未认证;1 已认证)
	Status               string `json:"status"`                  //状态(0 注销;1 正常; 2 封禁)
	Auth                 string `json:"auth"`                    //权限
	Balance              string `json:"balance"`                 //当前芝草
	ThisMonthUsedBalance string `json:"this_month_used_balance"` //本月兑换芝草
	HistoryBalance       string `json:"history_balance"`         //历史芝草
	RegisterTimeStart    string `json:"register_time_start"`     //注册时间起
	RegisterTimeEnd      string `json:"register_time_end"`       //注册时间止
	LastLoginTimeStart   string `json:"last_login_time_start"`   //最后一次登录时间起
	LastLoginTimeEnd     string `json:"last_login_time_end"`     //最后一次登录时间止
}

func (*ExportUser) Configure(rc *exl.WriteConfig) {}
func BatchExportUserHandler(ctx iris.Context) {
	var RequestParams ExportUserRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	type SystemUser struct {
		dao.SystemUser
		ThisMonthAmount string `json:"this_month_amount"`
		HistoryGet      string `json:"history_get"`
		HistoryPay      string `json:"history_pay"`
	}
	//判断权限
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	var serve services.CommonService[SystemUser]
	/*if claims.Type == 2 {
		var admin dao.Common[dao.SystemAdmin]
		admin.Query = map[string]interface{}{"id": claims.Id}
		systemAdmin, err := admin.First(admin.Query)
		if err != nil {
			ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
			return
		}
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("team_number IN ('%s')", strings.Join(systemAdmin.TeamPermissions, "','")))
	}*/
	if len(RequestParams.Ids) > 0 {
		ids := make([]string, len(RequestParams.Ids))
		for i, id := range RequestParams.Ids {
			ids[i] = utils.UintToString(id)
		}
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("tas_system_user.id in (%v) ", strings.Join(ids, ",")))
	}
	if utils.StringIsNotEmpty(RequestParams.UserId) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("user_id like '%%%v%%'", RequestParams.UserId))
	}
	if utils.StringIsNotEmpty(RequestParams.RealName) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("real_name like '%%%v%%'", RequestParams.RealName))
	}
	if utils.StringIsNotEmpty(RequestParams.NickName) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("nick_name like '%%%v%%'", RequestParams.NickName))
	}
	if utils.StringIsNotEmpty(RequestParams.TeamNumber) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("team_number like '%%%v%%'", RequestParams.TeamNumber))
	}
	if utils.StringIsNotEmpty(RequestParams.Phone) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("phone like '%%%v%%'", RequestParams.Phone))
	}
	if utils.StringIsNotEmpty(RequestParams.Email) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("email like '%%%v%%'", RequestParams.Email))
	}
	if utils.StringIsNotEmpty(RequestParams.IsAuthentication) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("is_authentication = %v ", RequestParams.IsAuthentication))
	}
	if utils.StringIsNotEmpty(RequestParams.Status) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("status = %v", RequestParams.Status))
	}
	if utils.StringIsNotEmpty(RequestParams.Auth) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("id in (SELECT DISTINCT(system_user_id) from tas_system_user_restriction WHERE project_id = '%v') ", RequestParams.Auth))
	}
	if utils.StringIsNotEmpty(RequestParams.Balance) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("balance = %v", RequestParams.Balance))
	}
	if utils.StringIsNotEmpty(RequestParams.RegisterTimeStart) && utils.StringIsNotEmpty(RequestParams.RegisterTimeEnd) {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("created_at >= '%v' and created_at <= '%v'", RequestParams.RegisterTimeStart, RequestParams.RegisterTimeEnd))
	}
	field := fmt.Sprintf("tas_system_user.*,")
	field += fmt.Sprintf("(select IFNULL(sum(amount),0) thisMonthAmount from tas_system_user_balance_log WHERE user_id = tas_system_user.user_id and log_type = 2 and left(created_at,7) = DATE_FORMAT(CURDATE(), '%%Y-%%m')) this_month_amount,")
	field += fmt.Sprintf("(select IFNULL(sum(amount),0) thisMonthAmount from tas_system_user_balance_log WHERE user_id = tas_system_user.user_id and log_type = 1) history_get,")
	field += fmt.Sprintf("(select IFNULL(sum(amount),0) thisMonthAmount from tas_system_user_balance_log WHERE user_id = tas_system_user.user_id and log_type = 2) history_pay")
	serve.SelectField = &field
	serve.PageSize = -1
	ExportData, err := serve.SelectList()
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	exportUserInfoRecords := make([]*ExportUser, len(ExportData.Data))
	for i, model := range ExportData.Data {
		exportUserInfoRecords[i] = &ExportUser{}
		exportUserInfoRecords[i].UserId = model.UserId
		exportUserInfoRecords[i].TeamNumber = model.TeamNumber
		exportUserInfoRecords[i].UserNumber = model.UserNumber
		exportUserInfoRecords[i].NickName = model.NickName
		exportUserInfoRecords[i].RealName = model.RealName
		exportUserInfoRecords[i].IsAuthentication = model.IsAuthentication
		exportUserInfoRecords[i].Phone = model.Phone
		exportUserInfoRecords[i].Email = model.Email
		exportUserInfoRecords[i].PassWord, _ = utils.Base64Decode(model.PassWord)
		exportUserInfoRecords[i].AlipayAccount = model.AlipayAccount
		exportUserInfoRecords[i].DeliveryAddress = model.DeliveryAddress
		exportUserInfoRecords[i].Introduction = model.Introduction
		exportUserInfoRecords[i].IdCardNumber = model.IdCardNumber
		exportUserInfoRecords[i].IdCardFace = model.IdCardFace
		exportUserInfoRecords[i].IdCardBack = model.IdCardBack
		exportUserInfoRecords[i].Balance = utils.Float64ToString(model.Balance) + "; " + model.ThisMonthAmount + "; " + model.HistoryPay + "; " + model.HistoryGet
		exportUserInfoRecords[i].Avatar = model.Avatar
		exportUserInfoRecords[i].Status = model.Status
		exportUserInfoRecords[i].CreatedAt = model.CreatedAt.Format(timehandler.FormatLayoutTime)
		exportUserInfoRecords[i].LastLoginTime = model.LastLoginTime.Format(timehandler.FormatLayoutTime)
		if len(model.SystemUserRestriction) > 0 {
			userRestriction := ""
			for _, restriction := range model.SystemUserRestriction {
				userRestriction += restriction.ProjectId + ", " + utils.IntToString(restriction.Limit) + ", " + utils.IntToString(restriction.LowerLimit) + ", " + utils.UintToString(restriction.Cd) + ", " + utils.UintToString(restriction.DayLimit) + ", " + utils.UintToString(restriction.DayGiveUpLimit) + "; "
			}
			exportUserInfoRecords[i].UserRestriction = userRestriction
		} else {
			exportUserInfoRecords[i].UserRestriction = ""
		}
	}

	unix := time.Now().UnixNano()
	if err := exl.Write(fmt.Sprintf("./export/export_user_info_records_%d.xlsx", unix), exportUserInfoRecords); err != nil {
		fmt.Println("write excel err:" + err.Error())
		return
	}
	tempFilename := fmt.Sprintf("./export/export_user_info_records_%d.xlsx", unix)
	//删除本地临时文件
	defer os.Remove(tempFilename)
	bucketClient := oss.BucketClient{}
	readFile, _ := ioutil.ReadFile(fmt.Sprintf("./export/export_user_info_records_%d.xlsx", unix))
	bucketClient.UpBytes(readFile, fmt.Sprintf("task-assign/export/export_user_info_records_%d.xlsx", unix))
	ctx.JSON(utils.Response{Code: iris.StatusOK, Message: iris.StatusText(iris.StatusOK), Data: fmt.Sprintf("%s/task-assign/export/export_user_info_records_%d.xlsx", utils.ServerConf.AliOssConf.CallBackHost, unix)})
	return
}

type SystemUserImportsOpen struct {
	UserId                string `excel:"用户ID（必填）"`                                         //用户Id
	TeamNumber            string `excel:"团队编号(选填)"`                                         //团队编号(选填)
	UserNumber            string `excel:"编号（选填）"`                                           //用户编号
	NickName              string `excel:"昵称(选填)"`                                           //昵称
	RealName              string `excel:"姓名(选填)"`                                           //姓名
	IsAuthentication      string `excel:"实名状态(0表示未实名，1表示已实名）（选填)"`                          //是否实名认证，0 未认证;1 已认证;
	IdCardNumber          string `excel:"身份证号码（选填）"`                                        //身份证号码
	Phone                 string `excel:"手机号（邮箱和手机号2选一填写即可）"`                               //手机号
	Email                 string `excel:"邮箱（邮箱和手机号2选一填写即可）"`                                //邮箱
	PassWord              string `excel:"密码(必填)"`                                           //密码
	AlipayAccount         string `excel:"支付宝(选填)"`                                          //支付宝账号
	DeliveryAddress       string `excel:"收货地址(选填)"`                                         //收货地址
	Introduction          string `excel:"个人简介(选填)"`                                         //简介
	Status                string `excel:"登录权限（0：注销；1：正常；2：封禁）(选填)"`                         //0 注销;1 正常; 2 封禁
	SystemUserRestriction string `excel:"项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(必填)"` //项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)
	/*SystemUserRestrictionType string `excel:"权限变更类型（1：新增权限；2：删除权限；3：覆盖权限）(选填)"`                 //权限变更类型（1：新增权限；2：删除权限；3：覆盖权限）(选填)
	Balance                   string `excel:"强制变更芝草数量（选填）（不填表示不修改）（填了则修改芝草为此数值）"`               //强制变更芝草数量（选填）（不填表示不修改）（填了则修改芝草为此数值）
	BalanceLog                string `excel:"强制变更芝草数量通知文本"`                                     //强制变更芝草数量通知文本*/
}

func (*SystemUserImportsOpen) Configure(rc *exl.ReadConfig) {}

func SystemUserImportsOpenHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	if models, err := exl.Read[*SystemUserImportsOpen](file); err != nil {
		fmt.Println("read excel err:" + err.Error())
	} else {
		fmt.Printf("read excel num: %d\n", len(models))
		//var userServe services.UserService
		var userDao dao.Common[dao.SystemUser]
		var prohibitedWordsService services.SystemProhibitedWordsService
		//var commonDao dao.Common[dao.SystemUserBalanceLog]
		index := 0
		var res ImportsResponse
		for i, model := range models {
			//从第二行开始读取
			if i == 0 {
				continue
			}
			if count, err := userDao.Count(map[string]interface{}{"user_id": model.UserId}); err != nil {
				continue
			} else {
				userObj := dao.SystemUser{}
				//如果是老用户责跳过不新增
				if count > 0 {
					continue
				}
				userObj.UserId = model.UserId
				//检查user基本信息
				if model.TeamNumber != "" {
					userObj.TeamNumber = model.TeamNumber
				}
				if model.UserNumber != "" {
					userObj.UserNumber = model.UserNumber
				}
				if model.NickName != "" {
					userObj.NickName = model.NickName
				} else {
					userObj.NickName = prohibitedWordsService.GenerateRandomNickName(10)
				}
				if model.RealName != "" {
					userObj.RealName = model.RealName
				}
				if model.IsAuthentication != "" {
					userObj.IsAuthentication, err = strconv.Atoi(model.IsAuthentication)
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   5 + 1,
							Reason: "实名状态(0表示未实名，1表示已实名）数据格式不对",
						})
						continue
					}
				}
				if model.IdCardNumber != "" {
					userObj.IdCardNumber = model.IdCardNumber
				}
				if model.Phone != "" {
					userObj.Phone = model.Phone
				}
				if model.Email != "" {
					userObj.Email = model.Email
				}
				if model.PassWord != "" {
					userObj.PassWord = utils.Base64Encode(model.PassWord)
				}
				if model.AlipayAccount != "" {
					userObj.AlipayAccount = model.AlipayAccount
				}
				if model.DeliveryAddress != "" {
					userObj.DeliveryAddress = model.DeliveryAddress
				}
				if model.Introduction != "" {
					userObj.Introduction = model.Introduction
				}
				if model.Status != "" {
					userObj.Status, err = strconv.Atoi(model.Status)
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   14,
							Reason: "登录权限（0：注销；1：正常；2：封禁）(选填)数据格式不对",
						})
						continue
					}
				}
				if model.SystemUserRestriction != "" {
					for _, item := range strings.Split(model.SystemUserRestriction, "；") {
						if strings.TrimSpace(item) == "" {
							continue
						}
						items := strings.Split(item, ",")
						if len(items) != 6 {
							items = strings.Split(item, "，")
							if len(items) != 6 {
								res.ErrList = append(res.ErrList, code.ImportError{
									Number: i + 1,
									Cell:   15,
									Reason: "项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)数据格式不对",
								})
								break
							}
						}
						limit, err := strconv.Atoi(strings.TrimSpace(items[1]))
						if err != nil {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   15,
								Reason: "项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)数据格式不对",
							})
							break
						}
						lowerLimit, err := strconv.Atoi(strings.TrimSpace(items[2]))
						if err != nil {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   15,
								Reason: "项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)数据格式不对",
							})
							break
						}

						if lowerLimit > limit {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   15,
								Reason: "项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)数据格式不对",
							})
							break
						}
						cd, err := strconv.Atoi(strings.TrimSpace(items[3]))
						if err != nil {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   15,
								Reason: "项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)数据格式不对",
							})
							break
						}

						dayLimit, err := strconv.Atoi(strings.TrimSpace(items[4]))
						if err != nil {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   15,
								Reason: "项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)数据格式不对",
							})
							break
						}
						dayGiveUpLimit, err := strconv.Atoi(strings.TrimSpace(items[5]))
						if err != nil {
							res.ErrList = append(res.ErrList, code.ImportError{
								Number: i + 1,
								Cell:   15,
								Reason: "项目领取限制（项目ID，领取上限，领取下限，领取CD单位秒，当日领取上限，当日放弃上限）(选填)数据格式不对",
							})
							break
						}
						userObj.SystemUserRestriction = append(userObj.SystemUserRestriction, modelbase.SystemUserRestriction{
							ProjectId:      strings.TrimSpace(items[0]),
							LowerLimit:     lowerLimit,
							Limit:          limit,
							Cd:             uint(cd),
							DayLimit:       uint(dayLimit),
							DayGiveUpLimit: uint(dayGiveUpLimit),
						})
					}
				}
				/*var mouthed int
				if model.SystemUserRestrictionType != "" {
					mouthed, err = strconv.Atoi(model.SystemUserRestrictionType)
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   16,
							Reason: "权限变更类型（1：新增权限；2：删除权限；3：覆盖权限）(选填)数据格式不对",
						})
					}
					if arrays.Contains([]int{3, 1, 2}, mouthed) == -1 {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   16,
							Reason: "权限变更类型（1：新增权限；2：删除权限；3：覆盖权限）(选填)数据格式不对",
						})
					}
				}*/

				/*isLog := false
				if model.Balance != "" {
					userObj.Balance, err = strconv.ParseFloat(model.Balance, 64)
					if err != nil {
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Cell:   16,
							Reason: "强制变更芝草数量（选填）（不填表示不修改）（填了则修改芝草为此数值）数据格式不对",
						})
						break
					}
					isLog = true
				}*/
				if err := userDao.CreateOne(userObj).Error; err != nil {
					switch mysqlhandler.MysqlErrCode(err) {
					case mysqlhandler.ErrDuplicateEntryCode:
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Reason: "该条数据已经存在，请检查用户Id或手机号码是否已经存在系统中！"})
					default:
						res.ErrList = append(res.ErrList, code.ImportError{
							Number: i + 1,
							Reason: err.Error()})
					}
					res.FailRows += 1
					continue
				} else {
					var appServe services2.SystemUserService
					if user, err := appServe.VerifyLogin(userObj.UserId, model.PassWord); err != nil {
						continue
					} else {
						services2.PutSystemUserChan(*user)
					}
				}
				/*if isLog {
					var log dao.SystemUserBalanceLog
					log.UserId = userObj.UserId
					log.TeamNumber = userObj.TeamNumber
					log.RemainAmount = userObj.Balance
					log.Amount = userObj.Balance
					log.LogType = 1
					log.BusinessType = 3
					log.Remark = model.BalanceLog
					commonDao.CreateOne(log)
				}*/
			}
			index++
		}
		ctx.JSON(utils.Response{
			Code:    200,
			Message: "ok",
			Data:    res,
		})
		return
	}
}

func UserWhiteListHandler(ctx iris.Context) {
	var RequestParams UserListRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var userServe services.UserService

	//判断权限
	var claims services.CustomClaims
	if err := claims.ParseClaims(ctx); err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	wherestr := []string{}
	//if claims.Type == 2 {

	var admin dao.Common[dao.SystemAdmin]
	admin.Query = map[string]interface{}{"id": claims.Id}
	systemAdmin, err := admin.First(admin.Query)
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	wherestr = append(wherestr, fmt.Sprintf("team_number IN ('%s')", strings.Join(systemAdmin.TeamPermissions, "','")))
	//}
	if utils.StringIsNotEmpty(RequestParams.UserId) {
		wherestr = append(wherestr, fmt.Sprintf("tas_system_user.user_id like '%%%v%%'", RequestParams.UserId))
	}
	if utils.StringIsNotEmpty(RequestParams.RealName) {
		wherestr = append(wherestr, fmt.Sprintf("real_name like '%%%v%%'", RequestParams.RealName))
	}
	if utils.StringIsNotEmpty(RequestParams.NickName) {
		wherestr = append(wherestr, fmt.Sprintf("nick_name like '%%%v%%'", RequestParams.NickName))
	}
	if utils.StringIsNotEmpty(RequestParams.TeamNumber) {
		wherestr = append(wherestr, fmt.Sprintf("team_number like '%%%v%%'", RequestParams.TeamNumber))
	}
	if utils.StringIsNotEmpty(RequestParams.Phone) {
		wherestr = append(wherestr, fmt.Sprintf("phone like '%%%v%%'", RequestParams.Phone))
	}
	if utils.StringIsNotEmpty(RequestParams.Email) {
		wherestr = append(wherestr, fmt.Sprintf("email like '%%%v%%'", RequestParams.Email))
	}
	if utils.StringIsNotEmpty(RequestParams.IsAuthentication) {
		wherestr = append(wherestr, fmt.Sprintf("is_authentication = %v ", RequestParams.IsAuthentication))
	}
	if utils.StringIsNotEmpty(RequestParams.Status) {
		wherestr = append(wherestr, fmt.Sprintf("status = %v", RequestParams.Status))
	}
	if utils.StringIsNotEmpty(RequestParams.Auth) {
		wherestr = append(wherestr, fmt.Sprintf("id in (SELECT DISTINCT(system_user_id) from tas_system_user_restriction WHERE project_id = '%v') ", RequestParams.Auth))
	}
	if utils.StringIsNotEmpty(RequestParams.Balance) {
		wherestr = append(wherestr, fmt.Sprintf("balance = %v", RequestParams.Balance))
	}
	if utils.StringIsNotEmpty(RequestParams.RegisterTimeStart) && utils.StringIsNotEmpty(RequestParams.RegisterTimeEnd) {
		wherestr = append(wherestr, fmt.Sprintf("created_at >= '%v' and created_at <= '%v'", RequestParams.RegisterTimeStart, RequestParams.RegisterTimeEnd))
	}
	if res, err := userServe.GetUserWhiteList(RequestParams.Page, RequestParams.PageSize, wherestr); err != nil {
		ctx.JSON(utils.ResponseError{
			Code:    iris.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	} else {
		ctx.JSON(utils.Response{
			Code:    200,
			Message: "ok",
			Data:    iris.Map{"count": res.Total, "list": res.Data},
		})
		return
	}
}

type UserWhiteListImport struct {
	UserId string `excel:"用户ID（必填）"`
}

func (*UserWhiteListImport) Configure(rc *exl.ReadConfig) {}
func UserWhiteListImportHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	if models, err := exl.Read[*UserWhiteListImport](file); err != nil {
		fmt.Println("read excel err:" + err.Error())
		ctx.JSON(utils.ResponseServerError(errors.New("excel读取错误")))
		return
	} else {
		fmt.Printf("read excel num: %d\n", len(models))
		var userWhiteListObjs []*dao.SystemUserWhitelist
		index := 0
		for i, model := range models {
			//从第二行开始读取
			if i == 0 {
				continue
			}

			var userWhiteListObj dao.SystemUserWhitelist
			userWhiteListObj.UserId = model.UserId
			userWhiteListObjs = append(userWhiteListObjs, &userWhiteListObj)
			index++
		}
		var userServe services.UserService
		if err := userServe.UserWhiteListImport(userWhiteListObjs); err != nil {
			ctx.JSON(utils.ResponseServerError(err))
			return
		}
		ctx.JSON(utils.ResponseOK())
		return
	}
}

func UserWhiteListImportDelHandler(ctx iris.Context) {
	_, handle, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	file, _ := handle.Open()
	defer file.Close()
	if models, err := exl.Read[*UserWhiteListImport](file); err != nil {
		fmt.Println("read excel err:" + err.Error())
		ctx.JSON(utils.ResponseServerError(errors.New("excel读取错误")))
		return
	} else {
		fmt.Printf("read excel num: %d\n", len(models))
		var userWhiteListObjs []*dao.SystemUserWhitelist
		index := 0
		for i, model := range models {
			//从第二行开始读取
			if i == 0 {
				continue
			}

			var userWhiteListObj dao.SystemUserWhitelist
			userWhiteListObj.UserId = model.UserId
			userWhiteListObjs = append(userWhiteListObjs, &userWhiteListObj)
			index++
		}
		var userServe services.UserService
		if err := userServe.UserWhiteListImportDel(userWhiteListObjs); err != nil {
			ctx.JSON(utils.ResponseServerError(err))
			return
		}
		ctx.JSON(utils.ResponseOK())
		return
	}
}

type UserWhiteListDelRequest struct {
	UserIds []string `json:"user_ids" validate:"required"` //用户id
}

func UserWhiteListDelHandler(ctx iris.Context) {
	var RequestParams UserWhiteListDelRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	var userServe services.UserService
	if err := userServe.UserWhiteListDel(RequestParams.UserIds); err != nil {
		ctx.JSON(utils.ResponseServerError(err))
		return
	} else {
		ctx.JSON(utils.ResponseOK())
		return
	}
}

type ExportUserWhiteListRequest struct {
	UserIds []string `json:"user_ids"`
}

func (*ExportUserWhiteListRequest) Configure(rc *exl.WriteConfig) {}
func BatchExportUserWhiteListHandler(ctx iris.Context) {
	var RequestParams ExportUserWhiteListRequest
	if err := ctx.ReadJSON(&RequestParams); err != nil {
		handler.ArgumentErrorHandle(err, ctx)
		return
	}

	type SystemUser struct {
		dao.SystemUser
		ThisMonthAmount string `json:"this_month_amount"`
		HistoryGet      string `json:"history_get"`
		HistoryPay      string `json:"history_pay"`
	}
	var serve services.CommonService[SystemUser]
	if len(RequestParams.UserIds) > 0 {
		serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("tas_system_user.user_id in ('%s') ", strings.Join(RequestParams.UserIds, "','")))
	}
	serve.WhereStr = append(serve.WhereStr, fmt.Sprintf("tas_system_user_whitelist.user_id is not null"))
	field := fmt.Sprintf("tas_system_user.*,")
	field += fmt.Sprintf("(select IFNULL(sum(amount),0) thisMonthAmount from tas_system_user_balance_log WHERE user_id = tas_system_user.user_id and log_type = 2 and left(created_at,7) = DATE_FORMAT(CURDATE(), '%%Y-%%m')) this_month_amount,")
	field += fmt.Sprintf("(select IFNULL(sum(amount),0) thisMonthAmount from tas_system_user_balance_log WHERE user_id = tas_system_user.user_id and log_type = 1) history_get,")
	field += fmt.Sprintf("(select IFNULL(sum(amount),0) thisMonthAmount from tas_system_user_balance_log WHERE user_id = tas_system_user.user_id and log_type = 2) history_pay")
	serve.SelectField = &field
	serve.LeftJoin = append(serve.LeftJoin, fmt.Sprintf("LEFT JOIN tas_system_user_whitelist on tas_system_user.user_id = tas_system_user_whitelist.user_id "))
	serve.PageSize = -1
	ExportData, err := serve.SelectList()
	if err != nil {
		ctx.JSON(utils.ResponseError{Code: iris.StatusInternalServerError, Message: err.Error()})
		return
	}
	exportUserInfoRecords := make([]*ExportUser, len(ExportData.Data))
	for i, model := range ExportData.Data {
		exportUserInfoRecords[i] = &ExportUser{}
		exportUserInfoRecords[i].UserId = model.UserId
		exportUserInfoRecords[i].TeamNumber = model.TeamNumber
		exportUserInfoRecords[i].UserNumber = model.UserNumber
		exportUserInfoRecords[i].NickName = model.NickName
		exportUserInfoRecords[i].RealName = model.RealName
		exportUserInfoRecords[i].IsAuthentication = model.IsAuthentication
		exportUserInfoRecords[i].Phone = model.Phone
		exportUserInfoRecords[i].Email = model.Email
		exportUserInfoRecords[i].PassWord, _ = utils.Base64Decode(model.PassWord)
		exportUserInfoRecords[i].AlipayAccount = model.AlipayAccount
		exportUserInfoRecords[i].DeliveryAddress = model.DeliveryAddress
		exportUserInfoRecords[i].Introduction = model.Introduction
		exportUserInfoRecords[i].IdCardNumber = model.IdCardNumber
		exportUserInfoRecords[i].IdCardFace = model.IdCardFace
		exportUserInfoRecords[i].IdCardBack = model.IdCardBack
		exportUserInfoRecords[i].Balance = utils.Float64ToString(model.Balance) + "; " + model.ThisMonthAmount + "; " + model.HistoryPay + "; " + model.HistoryGet
		exportUserInfoRecords[i].Avatar = model.Avatar
		exportUserInfoRecords[i].Status = model.Status
		exportUserInfoRecords[i].CreatedAt = model.CreatedAt.Format(timehandler.FormatLayoutTime)
		exportUserInfoRecords[i].LastLoginTime = model.LastLoginTime.Format(timehandler.FormatLayoutTime)
		if len(model.SystemUserRestriction) > 0 {
			userRestriction := ""
			for _, restriction := range model.SystemUserRestriction {
				userRestriction += restriction.ProjectId + ", " + utils.IntToString(restriction.Limit) + ", " + utils.IntToString(restriction.LowerLimit) + ", " + utils.UintToString(restriction.Cd) + ", " + utils.UintToString(restriction.DayLimit) + ", " + utils.UintToString(restriction.DayGiveUpLimit) + "; "
			}
			exportUserInfoRecords[i].UserRestriction = userRestriction
		} else {
			exportUserInfoRecords[i].UserRestriction = ""
		}
	}

	unix := time.Now().UnixNano()
	if err := exl.Write(fmt.Sprintf("./export/export_user_white_list_records_%d.xlsx", unix), exportUserInfoRecords); err != nil {
		fmt.Println("write excel err:" + err.Error())
		return
	}
	tempFilename := fmt.Sprintf("./export/export_user_white_list_records_%d.xlsx", unix)
	//删除本地临时文件
	defer os.Remove(tempFilename)
	bucketClient := oss.BucketClient{}
	readFile, _ := ioutil.ReadFile(fmt.Sprintf("./export/export_user_white_list_records_%d.xlsx", unix))
	bucketClient.UpBytes(readFile, fmt.Sprintf("task-assign/export/export_user_white_list_records_%d.xlsx", unix))
	ctx.JSON(utils.Response{Code: iris.StatusOK, Message: iris.StatusText(iris.StatusOK), Data: fmt.Sprintf("%s/task-assign/export/export_user_white_list_records_%d.xlsx", utils.ServerConf.AliOssConf.CallBackHost, unix)})
	return
}
